<template>
    <div class="customBox modelBox">
        <h3 class="title">
            <el-input v-model="searchKey" clearable placeholder="关键字"></el-input>
            <el-button class="addButton" style="margin: 0 0 0 20px;" type="primary" size="mini" round @click="refresh" circle title="刷新">
                <i class="el-icon-refresh"></i>
            </el-button>
            <el-button class="addButton" type="success" size="mini" round @click="newModel" circle title="添加">
                <i class="el-icon-plus"></i>
            </el-button>
        </h3>
        <div class="customBox-body">
            <div class="empty" v-if="!items.length">
                暂无数据
            </div>
            <el-card class="box-card" v-for="(item, index) in items" :key="index" :body-style="{ padding: '0px' }">
                <div slot="header" class="clearfix">
                    <span>{{item.key}} <span style="color: #999;">{{item.name}}</span></span>
                    <el-button style="float: right; padding: 3px 0" type="text" @click="viewModel(item)">
                        <i class="el-icon-arrow-down" :class="{'show' : item.show}"></i>
                    </el-button>
                </div>
                <el-collapse-transition>
                    <div v-show="item.show" class="box-card-input">
                        <el-input v-model="item.text" readonly type="textarea" resize="none" :autosize="{ minRows: 2, maxRows: 20}">
                        </el-input>
                    </div>
                </el-collapse-transition>
                <div class="box-card-buttons">
                    <el-button size="mini" type="primary" icon="el-icon-check" round @click="useString(item)">载入
                    </el-button>
                    <el-button size="mini" type="warning" icon="el-icon-edit-outline" @click="editModel(item)" round>编辑
                    </el-button>
                    <el-button size="mini" type="danger" icon="el-icon-delete" round @click="deleteModel(item)">删除
                    </el-button>
                </div>
            </el-card>
        </div>
        <el-dialog title="模型编辑" append-to-body :close-on-click-modal="false" :class="theme" :visible.sync="showEditor" width="1000px">
            <el-row :gutter="5" style="padding: 0 0 5px 0;">
                <el-col :span="3" style="line-height: 40px;">类名:</el-col>
                <el-col :span="12">
                    <el-input v-model="activeObject.key" placeholder="类名不能为空"></el-input>
                </el-col>
                <el-col :span="9">
                    <el-button style="float: right;" icon="el-icon-edit-outline" @click="showJsonEditorEvent" round>
                        从代码中导入
                    </el-button>
                </el-col>
            </el-row>
            <el-row :gutter="5" style="padding: 0 0 5px 0;">
                <el-col :span="3" style="line-height: 40px;">备注 :</el-col>
                <el-col :span="12">
                    <el-input v-model="activeObject.name" placeholder="备注"></el-input>
                </el-col>
                <el-col :span="7" style="line-height: 40px;">&nbsp;</el-col>
                <el-col :span="2">
                    <el-button style="float: right; margin: 6px 0;" type="success" size="mini" title="添加子项" @click="addItem()" circle icon="el-icon-plus">
                    </el-button>
                </el-col>
            </el-row>

            <el-row :gutter="5" style="padding: 0 0 5px 0;" v-for="(formitem, index) in activeObject.itemArray" :key="index">
                <el-col :span="2">
                    <div class="required">
                        <el-checkbox v-model="formitem.checked">必填</el-checkbox>
                    </div>
                </el-col>
                <el-col :span="6">
                    <el-input v-model="formitem.key" placeholder="Key值"></el-input>
                </el-col>
                <el-col :span="4">
                    <el-select style="width: 100%;" :popper-class="theme" filterable default-first-option allow-create :class="theme" placeholder="请选择" v-model="formitem.type">
                        <el-option v-for="item in typeArray" :class="theme" :key="item.value" :label="item.label" :value="item.value">
                        </el-option>
                    </el-select>
                </el-col>
                <el-col :span="10">
                    <div>
                        <el-input placeholder="备注" v-model="formitem.annotate"></el-input>
                    </div>
                </el-col>
                <el-col :span="2">
                    <el-button style="float: right; margin: 6px 0;" type="danger" size="mini" @click="deleteItem(index)" circle icon="el-icon-delete">
                    </el-button>
                </el-col>
            </el-row>
            <span slot="footer" class="dialog-footer">
                <el-button type="primary" size="samll" @click="submitModel">提交</el-button>
            </span>
        </el-dialog>

        <el-dialog title="从代码中导入" append-to-body :close-on-click-modal="false" :class="theme" :visible.sync="showJavaEditor" width="600px">
            <el-radio v-model="formatType" label="JAVA">JAVA</el-radio>
            <el-radio v-model="formatType" label="#C">#C</el-radio>
            <el-radio v-model="formatType" label="MYSQL">MYSQL</el-radio>
            <el-radio v-model="formatType" label="ORACLE">ORACLE / GP</el-radio>
            <!-- <el-radio v-model="formatType" label="GP">GP</el-radio> -->
            <br>
            <br>
            <el-input class="CodeMirror-custom" type="textarea" :rows="10" resize="none" v-model="javaCode"></el-input>
            <span slot="footer" class="dialog-footer">
                <el-button type="primary" size="samll" @click="formatCode">导入</el-button>
            </span>
        </el-dialog>

    </div>
</template>
<script>
import { mapState } from 'vuex';
import formatCSCode from './formatCSCode.js'
export default {
    data() {
        return {
            formatType: 'JAVA',
            showJavaEditor: false,
            searchKey: '',
            showEditor: false,
            activeObject: {},
            javaCode: '',
        }
    },
    computed: {
        ...mapState("theme", {
            theme: state => state.theme,
        }),
        ...mapState("customKey", {
            editObj: state => state.activeObj,
            callbackEvent: state => state.callbackEvent,
        }),
        ...mapState("model", {
            models: state => state.models,
            typeArray: state => state.typeArray,
        }),
        items: function () {
            let _search = this.searchKey;
            let reg = new RegExp(_search, 'ig'); // 不区分大小写
            if (_search) {
                return this.models.filter(function (item) {
                    if (item.key.toString().match(reg) || item.name.toString().match(reg)) {
                        return item;
                    }
                });
            }
            return this.models;
        },
    },
    methods: {
        refresh() {
            this.$store.dispatch('model/getRenderData');
        },
        useString(item) {
            if (this.callbackEvent === null) {
                var str = this.renderData(item);
                str = (str.substring(str.length - 1) == ',') ? str.substring(0, str.length - 1) : str;
                this.editObj.setValue(str);
            } else {
                var str = this.renderDataToMarkDownString(item);
                this.callbackEvent(str);
            };
            this.$store.dispatch('customKey/colseCustomDrawer');
        },
        addItem(type, index) {
            this.activeObject.itemArray.push({
                key: '',
                type: 'String',
                annotate: '',
            });
        },
        newModel() {
            this.showEditor = true;
            this.activeObject = {
                modelId: false,
                key: '',
                name: '',
                itemArray: [{
                    checked: false,
                    key: '',
                    type: 'String',
                    annotate: '',
                }]
            };
        },
        viewModel(item) {
            if (item.show) {
                item.show = false;
            } else {
                var str = this.renderData(item);
                str = (str.substring(str.length - 1) == ',') ? str.substring(0, str.length - 1) : str;
                item.text = str;
                setTimeout(() => {
                    item.show = true;
                }, 10);
            }
        },
        inArray(string, _array) {
            var index = -1;
            for (let i = 0; i < _array.length; i++) {
                const element = _array[i];
                if (element == string) {
                    index = i;
                    break;
                };
            };
            return index;
        },
        beautify(source) {
            function looks_like_html(source) {
                var trimmed = source.replace(/^[ \t\n\r]+/, '');
                return trimmed && (trimmed.substring(0, 1) === '<');
            };
            var output,
                opts = {
                    // brace_style : "expand"
                };
            opts.indent_char = ' ';
            opts.preserve_newlines = "-1";
            if (looks_like_html(source)) {
                output = html_beautify(source, opts);
            } else {
                output = js_beautify(source, opts);
            };
            return output;
        },
        renderData(data, annotate) {
            let typeArray = ['long', 'Integer', 'short', 'byte', 'float', 'double', 'boolean', 'char', 'string', 'date', 'bigDecimal', 'timestamp'];
            typeArray = typeArray.concat(['decimal', 'double', 'float', 'tinyint', 'smallint', 'mediumint', 'int', 'bigint', 'year', 'time', 'date', 'datetime', 'timestamp', 'char', 'varchar', 'binary', 'varbinary', 'blob', 'text', 'enum', 'set', 'bit', 'binary', 'varbinary', 'tinyblob', 'mediumblob', 'longblob']);
            typeArray = typeArray.concat(['bfile', 'binary_double', 'binary_float', 'blob', 'char', 'charvarying', 'character', 'charactervarying', 'clob', 'date', 'decimal', 'doubleprecision', 'float', 'int', 'integer', 'intervaldaytosecond', 'intervalyeartomonth', 'long', 'longraw', 'longvarchar', 'nationalchar', 'nationalcharvarying', 'nationalcharacter', 'nationalcharactervarying', 'nchar', 'ncharvarying', 'nclob', 'number', 'numeric', 'nvarchar2', 'raw', 'rowid', 'real', 'smallint', 'timestamp', 'timestampwithlocaltimezone', 'timestampwithtimezone', 'urowid', 'varchar', 'varchar2']);
            typeArray = typeArray.concat(['bit', 'bool', 'box', 'bytea', 'char', 'cidr', 'circle', 'date', 'decimal', 'float4', 'float8', 'inet', 'int2', 'int4', 'int8', 'interval', 'json', 'jsonb', 'line', 'lseg', 'macaddr', 'money', 'numeric', 'path', 'point', 'polygon', 'serial2', 'serial4', 'serial8', 'text', 'time', 'timestamp', 'timestamptz', 'timetz', 'tsquery', 'tsvector', 'txid_snapshot', 'uuid', 'varbit', 'varchar', 'xml']);

            let Items = {};
            for (let i = 0; i < this.models.length; i++) {
                const element = this.models[i];
                Items[element.key] = element;
            };
            var _String = '{'
            if (annotate) {
                _String += annotate
            };
            var renderAnnotation = item => {
                return ' // ' + item.annotate + ' (' + item.type + ') ' + (item.checked ? '必填' : '') + '\n';
            };

            for (let i = 0; i < data.itemArray.length; i++) {
                var item = data.itemArray[i];
                var __type = item.type.replace(/ /g, '');
                if (this.inArray(__type.toLocaleLowerCase(), typeArray) >= 0) {
                    _String += ((item.key ? item.key : '\'\'') + ':' + '\'\',' + renderAnnotation(item));
                } else if (item.type.indexOf('List') >= 0) {
                    var _type = item.type.substring(item.type.indexOf('<') + 1, item.type.indexOf('>'));
                    if (this.inArray(_type.toLocaleLowerCase(), typeArray) >= 0) {
                        _String += ((item.key ? item.key : '\'\'') + ': [],' + renderAnnotation(item));
                    } else {
                        _String += ((item.key ? item.key : '\'\'') + ': [' + renderAnnotation(item));
                        if (Items.hasOwnProperty(_type)) {
                            _String += this.renderData(Items[_type]);
                        } else {
                            _String += ('{},\n');
                        };
                        _String += ('],\n');
                    };
                } else {
                    if (Items.hasOwnProperty(__type)) {
                        _String += (item.key + ': ');
                        _String += this.renderData(Items[__type], renderAnnotation(item));
                        _String += ('\n');
                    } else {
                        _String += (item.key + ': {},' + renderAnnotation(item));
                    };
                }
            };
            _String += '},'
            return this.beautify(_String)
        },
        editModel(item) {
            this.showEditor = true;
            // console.log(item);


            this.activeObject = JSON.parse(JSON.stringify(item));
        },
        showJsonEditorEvent() {
            this.showJavaEditor = true;
            this.javaCode = '';
        },
        deleteModel(item) {
            var confirm = this.$confirm('是否删除数据模型？');
            if (confirm) {
                this.$store.dispatch('model/deleteModel', item.modelId);
            };
        },
        submitModel() {
            if (!this.activeObject.key) {
                this.$message.error('类名不能为空');
                return;
            };
            if (!this.activeObject.name) {
                this.$message.error('备注不能为空');
                return;
            };
            if (!this.activeObject.itemArray.length) {
                this.$message.error('至少填写一项数据');
                return;
            };
            if (!this.activeObject.modelId) {
                var confirm = this.$confirm('是否创建数据模型？');
                if (confirm) {
                    this.$store.dispatch('model/creatModel', {
                        key: this.activeObject.key,
                        name: this.activeObject.name,
                        itemArray: this.activeObject.itemArray,
                        callback: () => {
                            this.showEditor = false;
                        }
                    });
                };
            } else {
                var confirm = this.$confirm('是否更新数据模型？');
                if (confirm) {
                    this.$store.dispatch('model/updateModel', {
                        id: this.activeObject.modelId,
                        key: this.activeObject.key,
                        name: this.activeObject.name,
                        itemArray: this.activeObject.itemArray,
                        callback: () => {
                            this.showEditor = false;
                        }
                    });
                };
            };
        },
        deleteItem(index) {
            this.activeObject.itemArray.splice(index, 1);
        },
        formatCode() {
            switch (this.formatType) {
                case 'JAVA':
                    this.formatJavaCode();
                    break;
                case 'MYSQL':
                    this.formatSQLCode(11);
                    break;
                case 'ORACLE':
                    this.formatSQLCode(6);
                    break;
                case 'C#':
                    this.formatCSCode();
                    break;
                default:
                    break;
            }
        },

        renderDataToMarkDownString(data) {
            var str = '';
            str += '###### ' + data.name + '(' + data.key + ')' + '\n';
            str += '|参数名|必选|类型|说明|\n|:----    |:---|:----- |-----   |\n';
            for (let d = 0; d < data.itemArray.length; d++) {
                const item = data.itemArray[d];
                str += '|' + item.key + '|' + (item.checked ? '是' : '否') + '|' + item.type + '|' + item.annotate + '|\n';
            }
            str += '\n';
            return str;
        },
        formatSQLCode(num) {
            var modelArray = this.javaCode.split('\n');
            var itemArray = [];
            for (let i = 0; i < modelArray.length; i++) {
                const element = modelArray[i];
                var _array = element.split('	');
                if (_array.length > 3) {
                    // console.log(element);
                    var _obj = {
                        key: _array[0].toLocaleLowerCase().replace(/\_(\w)/g, function (all, letter) {
                            return letter.toUpperCase();
                        }),
                        type: _array[1],
                        annotate: _array[num],
                        checked: (_array[4] == -1 ? false : true),
                    };
                    itemArray.push(_obj);
                };
            };
            this.activeObject.itemArray = itemArray;
            this.showJavaEditor = false;
        },
        formatCSCode(){
           var str = formatCSCode(this.javaCode);
        },
        formatJavaCode() {
            var classNameReg = new RegExp("(?<=public class )[^ ]+");
            var modelKey = this.javaCode.match(classNameReg);

            var itemArray = [];
            var _stringArray = this.javaCode.split('//');
            for (let index = 0; index < _stringArray.length; index++) {
                let element = '//' + _stringArray[index];
                if (index != 0) {
                    var typeReg = new RegExp("(?<=private ).+(?=;)");
                    var typeString = element.match(typeReg)[0];
                    var _typeStringArray = typeString.split(' ');
                    var key = _typeStringArray[1];
                    var type = _typeStringArray[0];

                    var annotateReg = new RegExp("(?<=\/\/ ).+(?=\n)");
                    var annotate = element.match(annotateReg)[0];
                    var _obj = {
                        key: key,
                        type: type,
                        annotate: annotate,
                    };
                    itemArray.push(_obj);
                };
            };

            var _stringArray_ = 'public class' + this.javaCode.split('public class')[1];
            if (_stringArray_) {
                _stringArray_ = _stringArray_.split('/*');
                for (let index = 0; index < _stringArray_.length; index++) {
                    let element = '/*' + _stringArray_[index];
                    if (index != 0) {
                        var typeReg = new RegExp("(?<=private ).+(?=;)");
                        var typeString = element.match(typeReg)[0];
                        var _typeStringArray = typeString.split(' ');
                        var key = _typeStringArray[1];
                        var type = _typeStringArray[0];

                        var annotateReg = new RegExp("(/\\\*([^*]|[\\\r\\\n]|(\\\*+([^*/]|[\\\r\\\n])))*\\\*+/)|(//.*)");
                        var annotate = element.match(annotateReg)[0];
                        annotate = annotate.replace(/\//g, '').replace(/\*/g, '').replace(/\s/g, '').replace(/\n/g, '');
                        // console.log(annotate);
                        var _obj = {
                            key: key,
                            type: type,
                            annotate: annotate,
                        };
                        itemArray.push(_obj);
                    };
                };
            }
            this.activeObject.key = modelKey[0];
            this.activeObject.itemArray = itemArray;
            this.showJavaEditor = false;
        },
    },
}
</script>
<style scoped>
    .title {
        display: flex;
        height: 40px;
        align-items: center;
    }

    .required { 
        line-height: 40px;
    }

    .title .key {
        color: #666;
    }

    .addButton {
        width: 28px;
        height: 28px;
    }

    .box-card {
        margin: 0 0 20px 0;
    }


    .box-card .el-icon-arrow-down {
        transition: transform .2s;
    }

    .box-card .el-icon-arrow-down.show {
        transform: rotateZ(-180deg);
    }

    .box-card-buttons {
        margin: -1px 0 0 0;
        padding: 20px;
        border-top: 1px solid #EBEEF5;
        position: relative;
        text-align: right;
    }

    .empty {
        text-align: center;
        line-height: 100px;
        color: #aaa;
    }


    /* .box-card-input {
        margin: 0 0 41px 0;
    } */
</style>